/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: Robot.java Package: tc.de.krawallmann.robobridge.devices Version: 1.0
 * Author(s): KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.devices;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

import tc.de.krawallmann.robobridge.communication.Command;
import tc.de.krawallmann.robobridge.communication.CommandType;
import tc.de.krawallmann.robobridge.communication.IncomingCommandListener;

/**
 * The Class Robot contains all devices.
 * 
 * @author KrawallMann
 * @version 1.0
 */
public class Robot implements IncomingCommandListener {

	/** The devices. */
	private transient final Map<Integer, AbstractDevice> devices =
			new HashMap<Integer, AbstractDevice>();

	/** The incoming commands. */
	private transient final Queue<Command> incomingCommands = new LinkedList<Command>();

	/** The model. */
	private String model = "";

	/** The model id. */
	private int modelId;

	/** The outgoing commands. */
	private transient final Queue<Command> outgoingCommands = new LinkedList<Command>();

	/**
	 * Adds the device.
	 * 
	 * @param device
	 *            the device
	 */
	public void addDevice(final AbstractDevice device) {
		devices.put(device.getDeviceId(), device);
	}

	/**
	 * Clear devices.
	 */
	public void clearDevices() {
		devices.clear();
	}

	/**
	 * Discard all commands.
	 */
	public void discardAllCommands() {
		incomingCommands.clear();
		outgoingCommands.clear();
	}

	/**
	 * Gets the device.
	 * 
	 * @param deviceId
	 *            the device id
	 * @return the device
	 */
	public AbstractDevice getDevice(final int deviceId) {
		return devices.get(deviceId);
	}

	public Collection<AbstractDevice> getDevices() {
		return devices.values();
	}

	/**
	 * Gets the model.
	 * 
	 * @return the model
	 */
	public String getModel() {
		return model;
	}

	/**
	 * Gets the model id.
	 * 
	 * @return the model id
	 */
	public int getModelId() {
		return modelId;
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * basepackage.IncomingCommandListener#onCommandReceived(basepackage.Command
	 * )
	 */
	@Override
	public boolean onCommandReceived(final Command command) {
		queueIncomingingCommand(command);
		return true;
	}

	/**
	 * Poll outgoing command.
	 * 
	 * @return the command
	 */
	public Command pollOutgoingCommand() {
		synchronized (outgoingCommands) {
			return outgoingCommands.poll();
		}
	}

	/**
	 * Process incoming.
	 */
	public void processIncoming() {
		synchronized (incomingCommands) {
			for (final Command command : incomingCommands) {
				processCommand(command);
			}
			incomingCommands.clear();
		}
	}

	/**
	 * Queue incominging command.
	 * 
	 * @param command
	 *            the command
	 */
	public void queueIncomingingCommand(final Command command) {
		if (command == null) {
			throw new IllegalArgumentException("Command is null!");
		}
		synchronized (incomingCommands) {
			incomingCommands.add(command);
		}
	}

	/**
	 * Queue outgoing command.
	 * 
	 * @param command
	 *            the command
	 */
	public void queueOutgoingCommand(final Command command) {
		if (command == null) {
			throw new IllegalArgumentException("Command is null!");
		}
		synchronized (outgoingCommands) {
			outgoingCommands.add(command);
		}
	}

	/**
	 * Removes the device.
	 * 
	 * @param device
	 *            the device
	 */
	public void removeDevice(final AbstractDevice device) {
		if (device == null) {
			throw new IllegalArgumentException("AbstractDevice is null!");
		}
		devices.remove(device.getDeviceId());
	}

	/**
	 * Sets the model.
	 * 
	 * @param model
	 *            the new model
	 */
	public void setModel(final String model) {
		this.model = model;
	}

	/**
	 * Sets the model id.
	 * 
	 * @param modelId
	 *            the new model id
	 */
	public void setModelId(final int modelId) {
		this.modelId = modelId;
	}

	/**
	 * Update hardware.
	 */
	public void updateHardware() {
		for (final AbstractDevice d : devices.values()) {
			d.update();
		}
	}

	/**
	 * Process command.
	 * 
	 * @param command
	 *            the command
	 */
	protected void processCommand(final Command command) {
		if (command == null) {
			throw new IllegalArgumentException("Command is null!");
		}
		if (command.getType() == CommandType.UPDATE_DEVICE_DATA) {
			for (final AbstractDevice device : devices.values()) {
				if(device.onCommandReceived(command)){
					return;
				}
			}

		}
		System.out.println("UNHANDLED COMMAND: "+command);
	}

}
